﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Driverplugin;
using Google.Protobuf;
using Grpc.Core;
using Grpc.Net.Client;
using IoTEdge.Grpc.Server.ABBLibs.config;
using IoTEdge.Grpc.Server.ABBLibs.entities;
using NLog;
using NLog.Fluent;
using StatusCode = Driverplugin.StatusCode;

namespace IoTEdge.Grpc.Server.ABBLibs.Base
{
    public class ABBCollect
    {
        CancellationTokenSource tokenSource = new CancellationTokenSource();
        public Logger logger = LogManager.GetCurrentClassLogger();
        public Metadata metaData = null;
        public ServerConfig Config = null;
        public Dictionary<string, DeviceModel> Instance = new Dictionary<string, DeviceModel>();

        AsyncDuplexStreamingCall<Response, DeviceLifeControlRequest>? lifeControl = null;
        Action act = null;
        DriverPlugin.DriverPluginClient client = null;

        // get server config
        public void GetServerConfig()
        {
            logger.Info("ABB驱动开始获取服务器配置信息!");
            Config = new();
            var str = Environment.GetEnvironmentVariable("IoTEdgeGrpcAddr", EnvironmentVariableTarget.Machine);
            if (string.IsNullOrEmpty(str))
                throw new ArgumentException("服务器地址未设置，请检查系统环境变量[IoTEdgeGrpcAddr]!");
            var strarr = str.Split(":");
            if (strarr.Length != 2)
                throw new ArgumentException("服务器地址不合法：" + str);
            Config.IP = strarr[0];
            Config.Port = strarr[1];
            logger.Info($"ABB驱动获取服务器配置信息成功！信息：{Config.ToString()}");
        }

        // connect to server and get access token
        public async Task GetAccessToken()
        {
            GrpcChannel channel = GrpcChannel.ForAddress($"http://{Config.IP}:{Config.Port}");
            client = new(channel);
            RegistrationRequest request = new RegistrationRequest();
            request.Schema = ByteString.CopyFrom(Encoding.UTF8.GetBytes(ABBDevice.GetSchema()));
            request.UiParam = ByteString.CopyFrom(Encoding.UTF8.GetBytes(ABBDevice.GetUI()));
            request.BuildIn = false;
            request.Name = "CustomABBProtocol";
            var response = await client.DriverRegistrationAsync(request);
            if (response.Token == "")
            {
                logger.Error($"ABB驱动从服务器 {Config.ToString()} 获取Token失败了！  错误信息: {response.Error}");
                client = null;
                return;
            }

            logger.Info($"ABB驱动成功的从IoTEdge服务器 {Config.ToString()}获取到了Token!  Token信息: {response.Token}");

            metaData = new Metadata();
            metaData.Add("Token", response.Token);
            var connresult = await client.ConnectAsync(new ConnectRequest(), metaData);
            if (connresult.StatusCode != StatusCode.StatusOk)
            {
                logger.Error($"ABB驱动连接到服务器{Config.ToString()}失败了！  错误状态码:{connresult.StatusCode} 错误信息: {connresult.ErrorMessage}");
                client = null;
            }
            else
            {
                logger.Info($"ABB驱动已成功连接到IoTEdge服务器： {Config.ToString()} ");
            }
        }

        public void MainInitInstance()
        {
            logger.Info("ABB驱动开始初始化...");
            lifeControl = client.DeviceLifeControl(metaData);
            _ = Task.Run(handleLifeControl);
        }

        // start server
        public async void Start(CancellationToken token, Action act)
        {
            this.act = act;
            token.Register(async () =>
            {
                tokenSource.Cancel();
                foreach (var item in Instance.Keys.ToArray())
                {
                    var model = Instance[item];
                    model.TokenSource.Cancel();
                    await Task.Delay(1000);
                }
            });
            try
            {
                GetServerConfig();
                await GetAccessToken();
                MainInitInstance();
            }
            catch (Exception exp)
            {
                logger.Fatal($"ABB驱动意外停止!错误消息：{exp.Message}...\n\t 堆栈信息: {exp.StackTrace}");
                return;
            }
        }
        //生命周期控制
        public virtual async void handleLifeControl()
        {
            try
            {
                var responseStream = lifeControl.ResponseStream;
                while (await responseStream.MoveNext(tokenSource.Token))
                {
                    DeviceLifeControlRequest req = responseStream.Current;
                    var rsp = new Response();
                    rsp.RequestID = req.RequestID;
                    rsp.StatusCode = Driverplugin.StatusCode.StatusOk;
                    switch (req.Command)
                    {
                        case DeviceLifeControlRequest.Types.DeviceLifeControlCommand.StartDevice:
                            logger.Info($"ABB驱动接收命令【StartDrivice】 【设备ID】:{req.Meta.Defination.DeviceID} 【设备名】:{req.Meta.Defination.DeviceName}");
                            StartDevice(req.Meta, ref rsp);
                            break;
                        case DeviceLifeControlRequest.Types.DeviceLifeControlCommand.StopDevice:
                            logger.Info($"ABB驱动接收命令【StopDrivice】 【设备ID】:{req.Meta.Defination.DeviceID} 【设备名】:{req.Meta.Defination.DeviceName}");
                            StopDevice(req.Meta, ref rsp);
                            break;
                        default:
                            rsp.StatusCode = Driverplugin.StatusCode.UnsupportLifeCycleRequest;
                            break;
                    }
                    try
                    {
                        await lifeControl.RequestStream.WriteAsync(rsp);
                    }
                    catch (Exception exp)
                    {
                        logger.Error($"ABB驱动控制设备生命周期服务【handleLifeControl】意外退出！错误消息：{exp.Message},\n\t调用堆栈：{exp.StackTrace}");
                    }
                }
            }
            catch (Exception exp)
            {
                logger.Fatal($"ABB驱动控制设备生命周期服务【handleLifeControl】意外退出！错误消息：{exp.Message},\n\t调用堆栈：{exp.StackTrace}");
                //act?.Invoke();
            }
        }

        public void StartDevice(DeviceMeta device, ref Response rsp)
        {
            if (Instance.ContainsKey(device.Defination.DeviceID))
            {
                var x = JsonSerializer.Serialize(device);
            }
            else
            {
                var model = JsonSerializer.Deserialize<CustomProtocolModel>(device.Defination.DeviceExtensionConfig);
                // 将设备添加到设备实体
                Instance.Add(device.Defination.DeviceID, new DeviceModel()
                {
                    CustomProtocolModel = model,
                    DeviceMeta = device,
                    Interval = ConvertIntervalMS(device.Defination.CollectInterval),
                    Timeout = ConvertIntervalMS(device.Defination.Timeout)
                });
                Instance[device.Defination.DeviceID].SendMessage += SendMessageAction;
                Instance[device.Defination.DeviceID].ReportErr += SendStatus;
                Instance[device.Defination.DeviceID].run();
                Instance[device.Defination.DeviceID].TokenSource.Token.Register((x) =>
                {
                    var dev = x as DeviceModel;
                    if (Instance.ContainsKey(dev.DeviceMeta.Defination.DeviceID))
                    {
                        Instance.Remove(dev.DeviceMeta.Defination.DeviceID);
                    }
                }, Instance[device.Defination.DeviceID]);
                logger.Info($"ABB驱动: 【设备ID】:{device.Defination.DeviceID} 已启动!");
            }
            rsp.StatusCode = StatusCode.StatusOk;
        }

        public void StopDevice(DeviceMeta device, ref Response response)
        {
            if (Instance.ContainsKey(device.Defination.DeviceID))
            {
                var dev = Instance[device.Defination.DeviceID];
                if (!dev.TokenSource.IsCancellationRequested)
                    dev.TokenSource.Cancel();
                dev.SendMessage -= SendMessageAction;
                dev.ReportErr -= SendStatus;
                logger.Info($"ABB驱动: 【设备ID】:{device.Defination.DeviceID} 已停止!");
                response.StatusCode = Driverplugin.StatusCode.StatusOk;
            }
            else
            {
                response.StatusCode = Driverplugin.StatusCode.StatusOk;
            }
        }

        //执行报告数据
        public void SendMessageAction(DeviceModel device, Driverplugin.Data data)
        {
            try
            {
                var msger = client.TransformData(metaData);
                msger.RequestStream.WriteAsync(data);
                data = null;
                GC.Collect();

            }
            catch (Exception exp)
            {
                logger.Error(exp, $"ABB驱动上报数据失败,错误信息: {exp.Message}");
            }
        }
        // 发送状态信息
        public async void SendStatus(DeviceModel dev, DeviceStatus.Types.DeviceState state, string msg)
        {
            HeartBeat hb = new HeartBeat();
            var status = state;
            var deviceStatus = new DeviceStatus();
            deviceStatus.State = status;
            deviceStatus.Error = msg;
            hb.DeviceStatus[dev.DeviceMeta.Defination.DeviceID] = deviceStatus;
            if (state == DeviceStatus.Types.DeviceState.ErrorState)
                logger.Error($"ABB驱动检测到数据采集异常，【设备ID】{dev.DeviceMeta.Defination.DeviceID}, 【错误信息】:{msg}");
            try
            {
                var msger = await client.SendHeartBeatAsync(hb, metaData);
                if (msger.StatusCode == Driverplugin.StatusCode.StatusOk)
                {
                    //logger.Info($"abb device id {dev.DeviceMeta.Defination.DeviceID} report a msg,status: {msger.StatusCode.ToString()}");
                }
                else
                {
                    logger.Error($"ABB驱动发送状态信息失败！【设备ID】 {dev.DeviceMeta.Defination.DeviceID} ,【错误代码】: {msger.StatusCode.ToString()}");
                }
            }
            catch (Exception exp)
            {
                logger.Error(exp
                    ,$"ABB驱动回复状态信息失败！【设备ID】 {dev.DeviceMeta.Defination.DeviceID} ,【错误信息】: {exp.Message}");
            }

        }
        // get collect time
        public int ConvertIntervalMS(string input)
        {
            int value = 1000;

            if (input.EndsWith("ms"))
            {
                input = input.Remove(input.Length - 2, 2);
                value = int.Parse(input);
            }
            else if (input.EndsWith("s"))
            {
                input = input.Remove(input.Length - 1, 1);
                value *= int.Parse(input);
            }
            else if (input.EndsWith("m"))
            {
                input = input.Remove(input.Length - 2, 1);
                value *= int.Parse(input);
                value *= 60;
            }
            else if (input.EndsWith("h"))
            {
                input = input.Remove(input.Length - 2, 1);
                value *= int.Parse(input);
                value *= 60 * 60;
            }
            else
            {
                value *= 30;
            }

            return value;
        }
    }
}